Next | Prev | Up | Top | Contents | Index
Synchronizing Within Upper-Half Functions
When designing an upper-half entry point, keep in mind that it could be executed concurrently with any other upper-half entry point, and that the one entry point could even be executed concurrently by multiple CPUs. Only a few entry points are immune:
- The pfxinit(), pfxedtinit(), and pfxstart() entry points cannot be entered concurrently with each other or any other entry point (pfxstart() could be entered concurrently with the interrupt handler).
- The pfxunload() and pfxhalt() entry points cannot be entered concurrently with any other entry point except for stray interrupts.
- Certain entry points have no cause to use shared data; for example, pfxsize() and pfxprint() normally do not need to take any precautions.
- Other upper-half entry points, and all STREAMS entry points, can be entered concurrently by multiple CPUs, when the driver is multiprocessor-aware.
You can deal with concurrency at different levels of sophistication.
Running on CPU 0
If you do not set the D_MP flag in a character driver or STREAMS driver (see "Flag D_MP"), the driver is executed only on CPU 0. As a result, upper-half entry points cannot execute concurrently, and the interrupt handler cannot run in true concurrency with an upper-half routine (although it can preempt an upper-half routine as it does in a uniprocessor).
The result is that user processes are serialized for the use of the driver for any purpose. Since CPU 0 is often busy with other housekeeping activities, access to the driver can have a latency that is long and variable.
Serializing on a Single Lock
You can create a single lock for upper-half serialization. Each upper-half function begins with read-only operations such as extracting the device minor number and testing and validating arguments. You allow these to execute concurrently on any CPU (the D_MP flag is set.)
In each enry point, when the preliminaries are complete, you acquire the single lock, and release it just before returning. The result is that processes are serialized for I/O through the driver. If the driver supports only a single device, processes would be serialized in any case, waiting for the device to operate. Since the upper half can execute on any CPU, latency is more predictable.
Serializing on a Lock Per Device
When the driver supports multiple minor devices, you will normally have a data structure per device, indexed by the device minor number. Typically an upper-half routine is concerned only with one minor device. You can define a lock in the data structure for the minor device, and acquire that lock as soon as the device number is known.
This permits concurrent execution of upper-half requests for different minor devices, while serializing access to any one device.
Next | Prev | Up | Top | Contents | Index